#include "teststdafx.h"
#include "stdafx.h"
#include <iostream>
#include <gtest/gtest.h>

#include "Business/ArbitrageLegs.h"
#include "Business/ClassicArbitrageContracts.h"
#include "Service/MarketStorage.h"
#include "Business/Customer.h"

using namespace std;
class ArbitrageLegsTest : public testing::Test
{
protected:

	virtual void SetUp()
	{
	}

	virtual void TearDown()
	{

	}
	Market const& CreateMarket0()
	{
		Variety variety("rb1010",1,10);

		Margins margins;
		margins.Add(Margin("test1",0.1));
		margins.Add(Margin("test2",0.2));
		variety.SetMargins(margins);
		Charge openExchageCharge("open exchange charge",Charge::PERCENT, 0.10);
		Charge openCompanyCharge("open company charge",Charge::PER_QUANTITY, 5);
		Charge offsetExchangeCharge("offset exchange charge",Charge::PER_QUANTITY, 10);
		Charge offsetCompanyCharge("offset company charge",Charge::PERCENT, 0.10);

		Charges openCharges;
		openCharges.push_back(openExchageCharge);
		openCharges.push_back(openCompanyCharge);
		Charges offsetCharges;
		offsetCharges.push_back(offsetExchangeCharge);
		offsetCharges.push_back(offsetCompanyCharge);

		variety.SetOperationCharges(Operation::OPEN, openCharges);
		variety.SetOperationCharges(Operation::OFFSET,offsetCharges);
		double lastPrice = 3000.00;
		Prices buyPrices;
		buyPrices[0] = Price(3010,7);
		Prices sellPrices;
		sellPrices[0] = Price(2990,6);
		double upperLimit = 4000.00;
		double lowerLimit = 2000.00;
		double preSettlementPrice  = 3100.00;
		Market market(0,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 
		return m_marketStorage.Save(market);
	}

	Market const& CreateMarket1()
	{
		Variety variety("rb1011",1,10);
		Margins margins;
		margins.Add(Margin("test1",0.1));
		margins.Add(Margin("test2",0.2));
		variety.SetMargins(margins);
		Charge openExchageCharge("open exchange charge",Charge::PERCENT, 0.10);
		Charge openCompanyCharge("open company charge",Charge::PER_QUANTITY, 5);
		Charge offsetExchangeCharge("offset exchange charge",Charge::PER_QUANTITY, 10);
		Charge offsetCompanyCharge("offset company charge",Charge::PERCENT, 0.10);

		Charges openCharges;
		openCharges.push_back(openExchageCharge);
		openCharges.push_back(openCompanyCharge);
		Charges offsetCharges;
		offsetCharges.push_back(offsetExchangeCharge);
		offsetCharges.push_back(offsetCompanyCharge);

		variety.SetOperationCharges(Operation::OPEN, openCharges);
		variety.SetOperationCharges(Operation::OFFSET,offsetCharges);
		double lastPrice = 3100.00;
		Prices buyPrices;
		buyPrices[0] = Price(3000,9);
		Prices sellPrices;
		sellPrices[0] = Price(2980,8);
		double upperLimit = 4000.00;
		double lowerLimit = 2000.00;
		double preSettlementPrice  = 3000.00;

		Market market(1,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 
		return m_marketStorage.Save(market);
	}
	MarketStorage m_marketStorage;
};


bool operator==(Leg const& l, Leg const& r)
{
	return l.GetContract() == r.GetContract() &&
		l.GetDirection() == r.GetDirection() &&
		l.GetOperation() == r.GetOperation();
}

ostream& operator<<(ostream& os, Leg const& leg)
{
	return os << leg.GetContract() << leg.GetDirection() << leg.GetOperation();
}



TEST_F(ArbitrageLegsTest,LegNagtiveDirectionTest)
{
	Leg leg1(CreateMarket0(),Direction::SELL,Operation::OPEN);
	Leg leg2(CreateMarket1(),Direction::BUY,Operation::OPEN);

	EXPECT_EQ(Direction::BUY,leg1.NegateDirection());
	EXPECT_EQ(Direction::SELL,leg2.NegateDirection());
}

TEST_F(ArbitrageLegsTest,LegGetPriceTest)
{
	Leg leg1(CreateMarket0(),Direction::SELL,Operation::OPEN);
	Leg leg2(CreateMarket0(),Direction::BUY,Operation::OPEN);
	Leg leg3(CreateMarket0(),Direction::SELL,Operation::OFFSET_TODAY);
	Leg leg4(CreateMarket0(),Direction::BUY,Operation::OFFSET_TODAY);

	Market const& market = CreateMarket0();

	EXPECT_EQ(market.GetLowerLimit(),leg1.GetLimitPrice());
	EXPECT_EQ(market.GetUpperLimit(),leg2.GetLimitPrice());
	EXPECT_EQ(market.GetLowerLimit(),leg3.GetLimitPrice());
	EXPECT_EQ(market.GetUpperLimit(),leg4.GetLimitPrice());


	EXPECT_EQ(market.GetBuyPrices()[0].GetPrice(),leg1.GetPrice());
	EXPECT_EQ(market.GetSellPrices()[0].GetPrice(),leg2.GetPrice());
	EXPECT_EQ(market.GetBuyPrices()[0].GetPrice(),leg3.GetPrice());
	EXPECT_EQ(market.GetSellPrices()[0].GetPrice(),leg4.GetPrice());
}

TEST_F(ArbitrageLegsTest,LegGetQuantityTest)
{
	Leg leg1(CreateMarket0(),Direction::SELL,Operation::OPEN);
	Leg leg2(CreateMarket0(),Direction::BUY,Operation::OPEN);
	Leg leg3(CreateMarket0(),Direction::SELL,Operation::OFFSET_TODAY);
	Leg leg4(CreateMarket0(),Direction::BUY,Operation::OFFSET_TODAY);

	Market const& market = CreateMarket0();

	EXPECT_EQ(market.GetBuyPrices()[0].GetQuantity(),leg1.GetQuantity());
	EXPECT_EQ(market.GetSellPrices()[0].GetQuantity(),leg2.GetQuantity());
	EXPECT_EQ(market.GetBuyPrices()[0].GetQuantity(),leg3.GetQuantity());
	EXPECT_EQ(market.GetSellPrices()[0].GetQuantity(),leg4.GetQuantity());
}

TEST_F(ArbitrageLegsTest,LegGetChargeTest)
{
	Leg leg1(CreateMarket0(),Direction::SELL,Operation::OPEN);
	Leg leg2(CreateMarket0(),Direction::BUY,Operation::OPEN);
	Leg leg3(CreateMarket0(),Direction::SELL,Operation::OFFSET_TODAY);
	Leg leg4(CreateMarket0(),Direction::BUY,Operation::OFFSET_TODAY);
	Leg leg5(CreateMarket0(),Direction::SELL,Operation::OFFSET);
	Leg leg6(CreateMarket0(),Direction::BUY,Operation::OFFSET);

	Market const& market = CreateMarket0();

	EXPECT_DOUBLE_EQ(6120,leg1.GetCharge(2));
	EXPECT_DOUBLE_EQ(6080,leg2.GetCharge(2));
	EXPECT_DOUBLE_EQ(0,leg3.GetCharge(2));
	EXPECT_DOUBLE_EQ(0,leg4.GetCharge(2));
	EXPECT_DOUBLE_EQ(3110,leg5.GetCharge(1));
	EXPECT_DOUBLE_EQ(3090,leg6.GetCharge(1));
}

TEST_F(ArbitrageLegsTest,LegGetMarginAmountTest)
{
	Leg leg1(CreateMarket0(),Direction::SELL,Operation::OPEN);
	Leg leg2(CreateMarket0(),Direction::BUY,Operation::OPEN);
	Leg leg3(CreateMarket0(),Direction::SELL,Operation::OFFSET_TODAY);
	Leg leg4(CreateMarket0(),Direction::BUY,Operation::OFFSET_TODAY);
	Leg leg5(CreateMarket0(),Direction::SELL,Operation::OFFSET);
	Leg leg6(CreateMarket0(),Direction::BUY,Operation::OFFSET);

	Market const& market = CreateMarket0();

	EXPECT_DOUBLE_EQ(18600,leg1.GetMarginAmount(2));
	EXPECT_DOUBLE_EQ(9300,leg2.GetMarginAmount(1));
	EXPECT_DOUBLE_EQ(0,leg3.GetMarginAmount(2));
	EXPECT_DOUBLE_EQ(0,leg4.GetMarginAmount(2));
	EXPECT_DOUBLE_EQ(0,leg5.GetMarginAmount(2));
	EXPECT_DOUBLE_EQ(0,leg6.GetMarginAmount(2));
}

TEST_F(ArbitrageLegsTest,LegGetFreezeAmountTest)
{
	Leg leg1(CreateMarket0(),Direction::SELL,Operation::OPEN);
	Leg leg2(CreateMarket0(),Direction::BUY,Operation::OPEN);
	Leg leg3(CreateMarket0(),Direction::SELL,Operation::OFFSET_TODAY);
	Leg leg4(CreateMarket0(),Direction::BUY,Operation::OFFSET_TODAY);
	Leg leg5(CreateMarket0(),Direction::SELL,Operation::OFFSET);
	Leg leg6(CreateMarket0(),Direction::BUY,Operation::OFFSET);

	Market const& market = CreateMarket0();

	EXPECT_DOUBLE_EQ(24720,leg1.GetFreezeAmount(2));
	EXPECT_DOUBLE_EQ(24680,leg2.GetFreezeAmount(2));
	EXPECT_DOUBLE_EQ(0,leg3.GetFreezeAmount(2));
	EXPECT_DOUBLE_EQ(0,leg4.GetFreezeAmount(2));
	EXPECT_DOUBLE_EQ(6220,leg5.GetFreezeAmount(2));
	EXPECT_DOUBLE_EQ(6180,leg6.GetFreezeAmount(2));
}

TEST_F(ArbitrageLegsTest,LegMatchTest)
{
	Leg leg(CreateMarket0(),Direction::SELL,Operation::OPEN);

	EXPECT_EQ(false,leg.Match(1,leg.GetDirection(),leg.GetOperation()));
	EXPECT_EQ(false,leg.Match(0,leg.NegateDirection(),leg.GetOperation()));
	EXPECT_EQ(false,leg.Match(0,leg.GetDirection(),Operation::OFFSET));
	EXPECT_EQ(false,leg.Match(0,leg.GetDirection(),Operation::OFFSET_TODAY));
	EXPECT_EQ(true,leg.Match(leg.GetContract(),leg.GetDirection(),leg.GetOperation()));
}


TEST_F(ArbitrageLegsTest, CreateBearishTest)
{
	int major = 0;
	int minor = 1;
	ArbitrageContracts contracts(major,minor);
	Leg expectedNearbyOpenLeg(CreateMarket0(),Direction::SELL,Operation::OPEN);
	Leg expectedFartherOpenLeg(CreateMarket1(),Direction::BUY,Operation::OPEN);
	Leg expectedNearbyOffsetLeg(CreateMarket0(),Direction::BUY,Operation::OFFSET_TODAY);
	Leg expectedFartherOffsetLeg(CreateMarket1(),Direction::SELL,Operation::OFFSET_TODAY);
	ArbitrageLegs legs = ArbitrageLegs::CreateBearish(m_marketStorage,contracts);

	EXPECT_EQ(expectedNearbyOpenLeg,legs.GetNearbyOpenLeg());
	EXPECT_EQ(expectedFartherOpenLeg,legs.GetFartherOpenLeg());
	EXPECT_EQ(expectedNearbyOffsetLeg,legs.GetNearbyOffsetLeg());
	EXPECT_EQ(expectedFartherOffsetLeg,legs.GetFartherOffsetLeg());

	EXPECT_EQ(expectedNearbyOpenLeg,legs.GetMajorOpenLeg());
	EXPECT_EQ(expectedFartherOpenLeg,legs.GetMinorOpenLeg());
	EXPECT_EQ(expectedNearbyOffsetLeg,legs.GetMajorOffsetLeg());
	EXPECT_EQ(expectedFartherOffsetLeg,legs.GetMinorOffsetLeg());
}

TEST_F(ArbitrageLegsTest, CreateBullishTest)
{
	int major = 0;
	int minor = 1;
	ArbitrageContracts contracts(major,minor);
	Leg expectedNearbyOpenLeg(CreateMarket0(),Direction::BUY,Operation::OPEN);
	Leg expectedFartherOpenLeg(CreateMarket1(),Direction::SELL,Operation::OPEN);
	Leg expectedNearbyOffsetLeg(CreateMarket0(),Direction::SELL,Operation::OFFSET_TODAY);
	Leg expectedFartherOffsetLeg(CreateMarket1(),Direction::BUY,Operation::OFFSET_TODAY);
	ArbitrageLegs legs = ArbitrageLegs::CreateBullish(m_marketStorage,contracts);

	EXPECT_EQ(expectedNearbyOpenLeg,legs.GetNearbyOpenLeg());
	EXPECT_EQ(expectedFartherOpenLeg,legs.GetFartherOpenLeg());
	EXPECT_EQ(expectedNearbyOffsetLeg,legs.GetNearbyOffsetLeg());
	EXPECT_EQ(expectedFartherOffsetLeg,legs.GetFartherOffsetLeg());

	EXPECT_EQ(expectedNearbyOpenLeg,legs.GetMajorOpenLeg());
	EXPECT_EQ(expectedFartherOpenLeg,legs.GetMinorOpenLeg());
	EXPECT_EQ(expectedNearbyOffsetLeg,legs.GetMajorOffsetLeg());
	EXPECT_EQ(expectedFartherOffsetLeg,legs.GetMinorOffsetLeg());
}

TEST_F(ArbitrageLegsTest, BearishGetBalanceTest)
//void foo()
{
	ArbitrageContracts contracts(0,1);
	Market const& market0 = CreateMarket0();
	Market const& market1 = CreateMarket1();
	ArbitrageLegs legs = ArbitrageLegs::CreateBearish(m_marketStorage,contracts);

	double expectedOpenBalance = market1.GetSellPrices()[0].GetPrice() - market0.GetBuyPrices()[0].GetPrice();
	double expectedOffsetBalance = market1.GetBuyPrices()[0].GetPrice() - market0.GetSellPrices()[0].GetPrice();
	double expectedStopBalance = expectedOffsetBalance;

	EXPECT_DOUBLE_EQ(expectedOpenBalance,legs.GetOpenBalance());
	EXPECT_DOUBLE_EQ(expectedOffsetBalance,legs.GetOffsetBalance());
	EXPECT_DOUBLE_EQ(expectedStopBalance,legs.GetStopBalance());
}

TEST_F(ArbitrageLegsTest, BullishGetBalanceTest)
//void foo()
{
	ArbitrageContracts contracts(0,1);
	Market const& market0 = CreateMarket0();
	Market const& market1 = CreateMarket1();
	ArbitrageLegs legs = ArbitrageLegs::CreateBullish(m_marketStorage,contracts);

	double expectedOpenBalance = market1.GetBuyPrices()[0].GetPrice() - market0.GetSellPrices()[0].GetPrice();
	double expectedOffsetBalance = market1.GetSellPrices()[0].GetPrice() - market0.GetBuyPrices()[0].GetPrice();
	double expectedStopBalance = expectedOffsetBalance;

	EXPECT_DOUBLE_EQ(expectedOpenBalance,legs.GetOpenBalance());
	EXPECT_DOUBLE_EQ(expectedOffsetBalance,legs.GetOffsetBalance());
	EXPECT_DOUBLE_EQ(expectedStopBalance,legs.GetStopBalance());
}

TEST_F(ArbitrageLegsTest, BearishGetBalanceByDealingTest)
// void foo()
{
	Market const& market0 = CreateMarket0();
	Market const& market1 = CreateMarket1();
	ArbitrageContracts contracts(0,1);
	ArbitrageLegs legs = ArbitrageLegs::CreateBearish(m_marketStorage,contracts);
	
	{
		Order order0 = {0};
		strcpy_s(order0.contractCode,market0.GetCode());
		order0.contract = market0.GetContract();
		order0.direction = legs.GetMajorOpenLeg().GetDirection();
		order0.operation = legs.GetMajorOpenLeg().GetOperation();
		order0.quantity = 10;
		order0.price = 3000.00;
		Customer customer("","","");
		Dealing dealing0(customer,order0);
		dealing0.OnOrdered("SystemNo");
		Trade trade(dealing0,3000.00,10,"SystemNo");
		dealing0.OnTrade(trade);

		double expectedOpenBalance = market1.GetSellPrices()[0].GetPrice() - dealing0.GetAverageDealPrice();
		double expectedOffsetBalance = market1.GetBuyPrices()[0].GetPrice() - dealing0.GetAverageDealPrice();
		double expectedStopBalance = expectedOffsetBalance;


		EXPECT_DOUBLE_EQ(expectedOpenBalance,legs.GetOpenBalance(dealing0));
		EXPECT_DOUBLE_EQ(expectedOffsetBalance,legs.GetOffsetBalance(dealing0));
		EXPECT_DOUBLE_EQ(expectedStopBalance,legs.GetStopBalance(dealing0));
	}

	{
		Order order1 = {0};
		strcpy_s(order1.contractCode,market1.GetCode());
		order1.contract = market1.GetContract();
		order1.direction = legs.GetMinorOpenLeg().GetDirection();
		order1.operation = legs.GetMinorOpenLeg().GetOperation();
		order1.quantity = 10;
		order1.price = 3000.00;
		Customer customer("","","");
		Dealing dealing1(customer,order1);
		dealing1.OnOrdered("SystemNo");
		Trade trade(dealing1,3000.00,10,"SystemNo");
		dealing1.OnTrade(trade);

		double expectedOpenBalance = dealing1.GetAverageDealPrice() - market0.GetBuyPrices()[0].GetPrice();
		double expectedOffsetBalance = dealing1.GetAverageDealPrice() - market0.GetSellPrices()[0].GetPrice();
		double expectedStopBalance = expectedOffsetBalance;

		EXPECT_DOUBLE_EQ(expectedOpenBalance,legs.GetOpenBalance(dealing1));
		EXPECT_DOUBLE_EQ(expectedOffsetBalance,legs.GetOffsetBalance(dealing1));
		EXPECT_DOUBLE_EQ(expectedStopBalance,legs.GetStopBalance(dealing1));

	}
}

TEST_F(ArbitrageLegsTest, BullishGetBalanceByDealingTest)
// void foo()
{
	Market const& market0 = CreateMarket0();
	Market const& market1 = CreateMarket1();
	ArbitrageContracts contracts(0,1);
	ArbitrageLegs legs = ArbitrageLegs::CreateBullish(m_marketStorage,contracts);

	{
		Order order0 = {0};
		strcpy_s(order0.contractCode,market0.GetCode());
		order0.contract = market0.GetContract();
		order0.direction = legs.GetMajorOpenLeg().GetDirection();
		order0.operation = legs.GetMajorOpenLeg().GetOperation();
		order0.quantity = 10;
		order0.price = 3000.00;
		Customer customer("","","");
		Dealing dealing0(customer,order0);
		dealing0.OnOrdered("SystemNo");
		Trade trade(dealing0,3000.00,10,"SystemNo");
		dealing0.OnTrade(trade);

		double expectedOpenBalance = market1.GetBuyPrices()[0].GetPrice() - dealing0.GetAverageDealPrice();
		double expectedOffsetBalance = market1.GetSellPrices()[0].GetPrice() - dealing0.GetAverageDealPrice();
		double expectedStopBalance = expectedOffsetBalance;


		EXPECT_DOUBLE_EQ(expectedOpenBalance,legs.GetOpenBalance(dealing0));
		EXPECT_DOUBLE_EQ(expectedOffsetBalance,legs.GetOffsetBalance(dealing0));
		EXPECT_DOUBLE_EQ(expectedStopBalance,legs.GetStopBalance(dealing0));
	}

	{
		Order order1 = {0};
		strcpy_s(order1.contractCode,market1.GetCode());
		order1.contract = market1.GetContract();
		order1.direction = legs.GetMinorOpenLeg().GetDirection();
		order1.operation = legs.GetMinorOpenLeg().GetOperation();
		order1.quantity = 10;
		order1.price = 3000.00;
		Customer customer("","","");
		Dealing dealing1(customer,order1);
		dealing1.OnOrdered("SystemNo");
		Trade trade(dealing1,3000.00,10,"SystemNo");
		dealing1.OnTrade(trade);

		double expectedOpenBalance = dealing1.GetAverageDealPrice() - market0.GetSellPrices()[0].GetPrice();
		double expectedOffsetBalance = dealing1.GetAverageDealPrice() - market0.GetBuyPrices()[0].GetPrice();
		double expectedStopBalance = expectedOffsetBalance;

		EXPECT_DOUBLE_EQ(expectedOpenBalance,legs.GetOpenBalance(dealing1));
		EXPECT_DOUBLE_EQ(expectedOffsetBalance,legs.GetOffsetBalance(dealing1));
		EXPECT_DOUBLE_EQ(expectedStopBalance,legs.GetStopBalance(dealing1));

	}
}

TEST_F(ArbitrageLegsTest, GetQuantityTest)
// void foo()
{
	Market const& market0 = CreateMarket0();
	Market const& market1 = CreateMarket1();
	ArbitrageContracts contracts(0,1);
	ArbitrageLegs bearishLegs = ArbitrageLegs::CreateBearish(m_marketStorage,contracts);
	ArbitrageLegs bullishLegs = ArbitrageLegs::CreateBullish(m_marketStorage,contracts);

	int expectedBearishOpenQuantity = min(market0.GetBuyPrices()[0].GetQuantity(),market1.GetSellPrices()[0].GetQuantity());
	int expectedBearishOffsetQuantity = min(market0.GetSellPrices()[0].GetQuantity(),market1.GetBuyPrices()[0].GetQuantity());

	int expectedBullishOpenQuantity = expectedBearishOffsetQuantity;
	int expectedBullishOffsetQuantity = expectedBearishOpenQuantity;

	EXPECT_EQ(expectedBearishOpenQuantity,bearishLegs.GetOpenQuantity());
	EXPECT_EQ(expectedBearishOffsetQuantity,bearishLegs.GetOffsetQuantity());
	EXPECT_EQ(expectedBullishOpenQuantity,bullishLegs.GetOpenQuantity());
	EXPECT_EQ(expectedBullishOffsetQuantity,bullishLegs.GetOffsetQuantity());
}

TEST_F(ArbitrageLegsTest, GetOpenFreezeAmountTest)
// void foo()
{
	ArbitrageContracts contracts(0,1);
	ArbitrageLegs bearishLegs = ArbitrageLegs::CreateBearish(m_marketStorage,contracts);
	ArbitrageLegs bullishLegs = ArbitrageLegs::CreateBullish(m_marketStorage,contracts);
	double expectedBearishOpenFreezeAmount = bearishLegs.GetFartherOpenLeg().GetFreezeAmount(1) + bearishLegs.GetNearbyOpenLeg().GetFreezeAmount(1);
	double expectedBullishOpenFreezeAmount = bullishLegs.GetFartherOpenLeg().GetFreezeAmount(1) + bullishLegs.GetNearbyOpenLeg().GetFreezeAmount(1);

	EXPECT_DOUBLE_EQ(expectedBearishOpenFreezeAmount,bearishLegs.GetOpenFreezeAmount(1));
	EXPECT_DOUBLE_EQ(expectedBullishOpenFreezeAmount,bearishLegs.GetOpenFreezeAmount(1));
}


TEST_F(ArbitrageLegsTest,UpdateBandTest)
{
	int major = 0;
	int minor = 1;
	ArbitrageContracts contracts(major,minor);
	ArbitrageLegs bearishLegs = ArbitrageLegs::CreateBearish(m_marketStorage,contracts);
	ArbitrageLegs bullishLegs = ArbitrageLegs::CreateBullish(m_marketStorage,contracts);

	double bearishOpen = 90;
	double bearishOffset = 120;
	double bearishStop = 60;
	Band bearishBand(bearishOpen, bearishOffset,bearishStop);

	double bullishOpen = 90;
	double bullishOffset = 60;
	double bullishStop = 120;
	Band bullishBand(bullishOpen, bullishOffset,bullishStop);

	EXPECT_EQ(true,bearishLegs.UpdateBand(bearishBand));
	EXPECT_EQ(false,bearishLegs.UpdateBand(bullishBand));

	EXPECT_EQ(false,bullishLegs.UpdateBand(bearishBand));
	EXPECT_EQ(true,bullishLegs.UpdateBand(bullishBand));
}
